package org.goldenport.g3

import scala.collection.immutable
import org.goldenport.util.QSymbolSet
import org.goldenport.util.ArrayMap
import org.goldenport.util.Control.or

/**
 * @since   Jun. 10, 2010
 * @version Nov. 28, 2010
 * @author  ASAMI, Tomoharu
 */
trait G3Message { //  def content: Any
  private val _properties = new ArrayMap[Symbol, Any]

  def normalize(ctx: G3AgentContext): Seq[G3Message] = List(this)

  def properties(props: (Symbol, Any)*): G3Message = {
    _properties ++= props
    this
  }

  def property(key: Symbol): Any = _properties(key)
  def propertyOption(key: Symbol): Option[Any] = {
    or(property_Sources) {
      msg: G3Message => msg.propertyOption(key)
    } orElse _properties.get(key)
  }

  protected def property_Sources: List[G3Message] = Nil
}

trait G3MimeTyped extends G3Message {
  def mimetype: String
}

trait G3TextMimeTyped extends G3MimeTyped {
  def toText: String
}

trait G3BinaryMimeTyped extends G3MimeTyped {
  def openInputStream: java.io.InputStream
}

// XXX uri, uri2?
abstract class G3Command(val uris: List[String]) extends G3Message {
  def this(uri: String) = this(List(uri))

  def uri: String = uris(0)
}

abstract class G3Signal extends G3Message {}

abstract class G3Control(val messages: G3Message*) extends G3Message with immutable.Seq[G3Message] {
  // Seq
  def apply(index: Int): G3Message = messages(index)
  def length: Int = messages.length
  def iterator: Iterator[G3Message] = messages.iterator

  //
  def copy(msgs: G3Message*): G3Message

  // evaluation in pipe execution
  def eval[B](f: G3Message => B): List[B] = {
    messages.flatMap {
      case control: G3Control => control.eval(f)
      case msg => List(f(msg))
    } toList
  }

  // normalize (e.g. bind variables) before pipe execution
  override def normalize(ctx: G3AgentContext) = {
    List(copy(messages.flatMap(_.normalize(ctx)): _*))
  }
}
